Skip to content

Conversation

birkskyum
Copy link
Member

@birkskyum birkskyum commented Sep 30, 2025

Supersedes

Summary by CodeRabbit

  • New Features

    • Added two end-to-end test applications demonstrating Solid Start with TanStack Router and Query integration
    • Added SSR query integration package for seamless server-to-client query data streaming
  • Tests

    • Added comprehensive Playwright end-to-end test suites covering navigation, query loading, and data fetching scenarios

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 30, 2025

Caution

Review failed

The head commit changed during the review from fdef491 to 9e9c471.

Walkthrough

Introduces two end-to-end test projects for TanStack Solid Router and Solid Query with complete build pipelines, file-based routing, API endpoints, and Playwright tests. Additionally, creates a new @tanstack/solid-router-ssr-query package for SSR query integration between Solid Router and Solid Query, enabling server-side query data fetching and hydration.

Changes

Cohort / File(s) Summary
E2E: Basic Solid Query
e2e/solid-start/basic-solid-query/package.json, playwright.config.ts, postcss.config.mjs, tailwind.config.mjs, tsconfig.json, vite.config.ts
Project configuration, build pipeline setup, Playwright e2e test runner, PostCSS/Tailwind theming, TypeScript and Vite SSR configuration for a Solid Start app.
E2E: Basic Solid Query – API Routes
e2e/solid-start/basic-solid-query/src/routes/api.users.ts, api/users.$id.ts
Server-side API routes fetching user data from external API or local test server, with environment-aware URL switching.
E2E: Basic Solid Query – File Routes
e2e/solid-start/basic-solid-query/src/routes/__root.tsx, index.tsx, posts.tsx, posts.$postId.tsx, posts.index.tsx, posts_.$postId.deep.tsx, users.tsx, users.$userId.tsx, users.index.tsx, deferred.tsx
File-based route definitions with loaders, error boundaries, nested routing, and UI components for posts, users, and deferred data scenarios.
E2E: Basic Solid Query – Utilities & Components
e2e/solid-start/basic-solid-query/src/components/DefaultCatchBoundary.tsx, NotFound.tsx; src/utils/posts.tsx, users.tsx, seo.ts; src/styles/app.css; src/routeTree.gen.ts, router.tsx
Query option helpers, error/not-found boundary components, SEO utilities, Tailwind styling, auto-generated route tree, and router factory.
E2E: Basic Solid Query – Tests
e2e/solid-start/basic-solid-query/tests/app.spec.ts, setup/global.setup.ts, setup/global.teardown.ts
Playwright e2e navigation tests and global test setup/teardown for dummy server lifecycle.
E2E: Query Integration
e2e/solid-start/query-integration/package.json, playwright.config.ts, postcss.config.mjs, tailwind.config.mjs, tsconfig.json, vite.config.ts
Project configuration, build pipeline, Playwright runner, and TypeScript/Vite setup for query integration e2e tests.
E2E: Query Integration – Routes & Utilities
e2e/solid-start/query-integration/src/routes/__root.tsx, index.tsx, useQuery.tsx, loader-fetchQuery/$type.tsx; src/queryOptions.ts; src/styles/app.css; src/routeTree.gen.ts, router.tsx
Route definitions demonstrating loader-driven and useQuery-based data fetching, query option factory, and route tree generation.
E2E: Query Integration – Tests
e2e/solid-start/query-integration/tests/app.spec.ts
Playwright e2e tests validating streaming query data in sync/async loader scenarios and useQuery integration.
SSR Query Integration Package
packages/solid-router-ssr-query/package.json, eslint.config.js, tsconfig.json, vite.config.ts, README.md
New package manifest, build config, ESLint rules, and documentation for SSR query integration.
SSR Query Integration Implementation
packages/solid-router-ssr-query/src/index.tsx
Core setupRouterSsrQueryIntegration function wrapping router render with QueryClientProvider for SSR hydration support.
Root Configuration
package.json
Workspace pnpm override for @tanstack/solid-router-ssr-query package resolution.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Server
    participant Router as Solid Router
    participant QueryClient as Query Client
    participant Provider as QueryClientProvider

    Note over Server: SSR Phase
    Server->>Router: Create router with QueryClient context
    Server->>QueryClient: setupRouterSsrQueryIntegration(router, queryClient)
    QueryClient->>QueryClient: Wrap render with QueryClientProvider
    Server->>Router: renderRouterToString()
    Router->>Router: Execute loaders (await ensureQueryData)
    Router->>QueryClient: Fetch queries server-side
    QueryClient-->>Router: Return query results
    Router-->>Server: HTML + serialized cache

    Note over Client: Hydration Phase
    Client->>Provider: Mount QueryClientProvider with serialized cache
    Provider->>QueryClient: Hydrate with server cache
    Client->>Router: Hydrate router
    Router->>Client: Resume from HTML (queries already available)
    Client->>Client: No refetch needed if cache fresh
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Rationale: While there are 50+ files, the majority are repetitive configuration (package.json, tsconfig.json, vite.config.ts, playwright.config.ts) across two similar e2e projects. The core complexity resides in: (1) route tree generation and type-level definitions (routeTree.gen.ts files—high-density TypeScript types), (2) new SSR integration logic in setupRouterSsrQueryIntegration, and (3) route definitions with loaders and query integration. Configuration homogeneity reduces overall effort, but route structures and SSR integration logic require focused review.

Possibly related PRs

Suggested labels

package: solid-router-ssr-query, package: solid-start, area: e2e-testing, type: feature

Suggested reviewers

  • schiller-manuel

Poem

🐰 A rabbit's ode to SSR queries flowing,
E2E tests dancing, hydration glowing,
Solid routes nested deep and wide,
With server-side queries on the ride,
SSR magic now by our side!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The PR title "solid-router-ssr-query" directly corresponds to the primary feature being introduced: a new package at packages/solid-router-ssr-query/ that provides SSR query integration between TanStack Solid Router and TanStack Solid Query. The title is specific, concise, and immediately communicates the core addition without being vague or overly broad. While the PR also includes two e2e test projects for Solid Start, these are supporting infrastructure that demonstrate and validate the main package functionality, making the package name the appropriate focal point for the title.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@nx-cloud
Copy link

nx-cloud bot commented Sep 30, 2025

View your CI Pipeline Execution ↗ for commit 9e9c471

Command Status Duration Result
nx affected --targets=test:eslint,test:unit,tes... ✅ Succeeded 5m 1s View ↗
nx run-many --target=build --exclude=examples/*... ✅ Succeeded 1m 25s View ↗

☁️ Nx Cloud last updated this comment at 2025-10-20 22:26:45 UTC

@pkg-pr-new
Copy link

pkg-pr-new bot commented Sep 30, 2025

More templates

@tanstack/arktype-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/arktype-adapter@5310

@tanstack/directive-functions-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/directive-functions-plugin@5310

@tanstack/eslint-plugin-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/eslint-plugin-router@5310

@tanstack/history

npm i https://pkg.pr.new/TanStack/router/@tanstack/history@5310

@tanstack/nitro-v2-vite-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/nitro-v2-vite-plugin@5310

@tanstack/react-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router@5310

@tanstack/react-router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router-devtools@5310

@tanstack/react-router-ssr-query

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router-ssr-query@5310

@tanstack/react-start

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start@5310

@tanstack/react-start-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-client@5310

@tanstack/react-start-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-server@5310

@tanstack/router-cli

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-cli@5310

@tanstack/router-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-core@5310

@tanstack/router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-devtools@5310

@tanstack/router-devtools-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-devtools-core@5310

@tanstack/router-generator

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-generator@5310

@tanstack/router-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-plugin@5310

@tanstack/router-ssr-query-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-ssr-query-core@5310

@tanstack/router-utils

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-utils@5310

@tanstack/router-vite-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-vite-plugin@5310

@tanstack/server-functions-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/server-functions-plugin@5310

@tanstack/solid-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-router@5310

@tanstack/solid-router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-router-devtools@5310

@tanstack/solid-router-ssr-query

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-router-ssr-query@5310

@tanstack/solid-start

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start@5310

@tanstack/solid-start-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-client@5310

@tanstack/solid-start-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-server@5310

@tanstack/start-client-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-client-core@5310

@tanstack/start-plugin-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-plugin-core@5310

@tanstack/start-server-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-core@5310

@tanstack/start-static-server-functions

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-static-server-functions@5310

@tanstack/start-storage-context

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-storage-context@5310

@tanstack/valibot-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/valibot-adapter@5310

@tanstack/virtual-file-routes

npm i https://pkg.pr.new/TanStack/router/@tanstack/virtual-file-routes@5310

@tanstack/zod-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/zod-adapter@5310

commit: 9e9c471

@birkskyum birkskyum force-pushed the solid-router-ssr-query branch from e2e737a to 197bd86 Compare October 20, 2025 17:49
@birkskyum birkskyum marked this pull request as ready for review October 20, 2025 17:49
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 12

🧹 Nitpick comments (23)
e2e/solid-start/basic-solid-query/src/utils/seo.ts (1)

1-6: Add explicit return type annotation.

For better type safety and IDE support, add an explicit return type annotation to the function.

Apply this diff to add a return type:

+type MetaTag = 
+  | { title: string }
+  | { name: string; content: string | undefined }
+
-export function seo(params: {
+export function seo(params: {
   title: string
   description?: string
   keywords?: string
   image?: string
-}) {
+}): MetaTag[] {

As per coding guidelines.

e2e/solid-start/basic-solid-query/src/components/NotFound.tsx (2)

11-16: Consider differentiating the button styling for better visual hierarchy.

Both action buttons use the same bg-cyan-600 color class. Other similar NotFound components in the codebase (e.g., examples/solid/start-basic/src/components/NotFound.tsx and e2e/solid-start/server-routes/src/components/NotFound.tsx) use distinct colors (bg-emerald-500 for "Go back" and bg-cyan-600 for "Start Over") to provide visual differentiation between the actions.

Apply this diff to match the pattern used elsewhere:

         <button
           onClick={() => window.history.back()}
-          class="bg-cyan-600 text-white px-2 py-1 rounded uppercase font-black text-sm"
+          class="bg-emerald-500 text-white px-2 py-1 rounded uppercase font-black text-sm"
         >
           Go back
         </button>

4-26: Consider adding a data-testid attribute for e2e testing.

The similar NotFound component in e2e/solid-start/server-routes/src/components/NotFound.tsx includes data-testid="default-not-found-component" on the container div, which facilitates more reliable e2e test assertions. Since this is also an e2e test project, adding a test identifier would improve testability.

Apply this diff:

 export function NotFound(props?: { children?: JSX.Element }) {
   return (
-    <div class="space-y-2 p-2">
+    <div class="space-y-2 p-2" data-testid="default-not-found-component">
       <div>
         {props?.children || 'The page you are looking for does not exist.'}
       </div>
e2e/solid-start/basic-solid-query/src/components/DefaultCatchBoundary.tsx (1)

1-4: Consider using a top-level type-only import for consistency.

ESLint flags the inline type specifier. While functional, separating type imports aligns with the import/consistent-type-specifier-style rule.

Apply this diff:

 import {
   ErrorComponent,
-  type ErrorComponentProps,
 } from '@tanstack/solid-router'
+import type { ErrorComponentProps } from '@tanstack/solid-router'
e2e/solid-start/basic-solid-query/src/routes/api/users.$id.ts (3)

18-23: Use template literal and add a timeout to reduce flakiness

Small cleanup and resilience: avoid string concat and set a short timeout on the request.

-          const res = await axios.get<User>(`${queryURL}/users/` + params.id)
+          const res = await axios.get<User>(`${queryURL}/users/${params.id}`, { timeout: 5000 })

24-27: Return upstream status when available; gate noisy logs

Differentiate 4xx vs 5xx to aid debugging, and avoid noisy console.error in green paths.

-        } catch (e) {
-          console.error(e)
-          return json({ error: 'User not found' }, { status: 404 })
-        }
+        } catch (e: any) {
+          if (import.meta.env.MODE !== 'test') console.error(e)
+          const status = e?.response?.status ?? 500
+          const body = status === 404 ? { error: 'User not found' } : { error: 'Request failed' }
+          return json(body, { status })
+        }

6-10: Environment variables are consistently defined in e2e config; refactor improves robustness

Vite uses dotenv to load additional environment variables from .env files, and the script output confirms that VITE_NODE_ENV and VITE_EXTERNAL_PORT are explicitly set in all playwright configs (both via command: shell environment and env: object properties). The code functions correctly within the e2e test harness.

However, the refactor suggestion remains valid as a defensive improvement. While the current setup works, adding fallbacks (using MODE as a standard Vite alternative and defaulting the port) hardens against misconfiguration outside the normal playwright execution path.

-let queryURL = 'https://jsonplaceholder.typicode.com'
-
-if (import.meta.env.VITE_NODE_ENV === 'test') {
-  queryURL = `http://localhost:${import.meta.env.VITE_EXTERNAL_PORT}`
-}
+const isTest = import.meta.env.VITE_NODE_ENV === 'test' || import.meta.env.MODE === 'test'
+const extPort = import.meta.env.VITE_EXTERNAL_PORT ?? '3001'
+const queryURL = isTest ? `http://localhost:${extPort}` : 'https://jsonplaceholder.typicode.com'
e2e/solid-start/basic-solid-query/package.json (1)

1-37: Switch internal deps to workspace:*; use srvx directly; move Vite to devDependencies

The codebase uses workspace:^ for internal packages, but guidelines require workspace:*. Additionally, srvx is available in devDependencies and Vite should move there since it's a build tool.

   "dependencies": {
     "@tanstack/solid-query": "^5.66.0",
     "@tanstack/solid-query-devtools": "^5.66.0",
-    "@tanstack/solid-router": "workspace:^",
-    "@tanstack/solid-router-devtools": "workspace:^",
-    "@tanstack/solid-router-ssr-query": "workspace:^",
-    "@tanstack/solid-start": "workspace:^",
+    "@tanstack/solid-router": "workspace:*",
+    "@tanstack/solid-router-devtools": "workspace:*",
+    "@tanstack/solid-router-ssr-query": "workspace:*",
+    "@tanstack/solid-start": "workspace:*",
     "solid-js": "^1.9.5",
     "redaxios": "^0.5.1",
     "tailwind-merge": "^2.6.0",
-    "vite": "^7.1.7"
   },
   "devDependencies": {
+    "vite": "^7.1.7",
     "@playwright/test": "^1.50.1",

And update the start script (line 11):

-    "start": "pnpx srvx --prod -s ../client dist/server/server.js",
+    "start": "srvx --prod -s ../client dist/server/server.js",
e2e/solid-start/query-integration/package.json (1)

1-36: Standardize workspace: protocol, move build-time dependencies, and make scripts hermetic*

  • Use workspace:* for internal packages per guidelines
  • Add srvx as devDependency (start script depends on it) and remove pnpx for reproducibility
  • Move Vite to devDependencies (build-time tool, not runtime)

Apply:

@@
   "dependencies": {
     "@tanstack/solid-query": "^5.66.0",
     "@tanstack/solid-query-devtools": "^5.66.0",
-    "@tanstack/solid-router": "workspace:^",
-    "@tanstack/solid-router-devtools": "workspace:^",
-    "@tanstack/solid-router-ssr-query": "workspace:^",
-    "@tanstack/solid-start": "workspace:^",
+    "@tanstack/solid-router": "workspace:*",
+    "@tanstack/solid-router-devtools": "workspace:*",
+    "@tanstack/solid-router-ssr-query": "workspace:*",
+    "@tanstack/solid-start": "workspace:*",
     "solid-js": "^1.9.5",
     "tailwind-merge": "^2.6.0",
-    "vite": "^7.1.7",
     "zod": "^3.24.2"
   },
   "devDependencies": {
     "@playwright/test": "^1.50.1",
-    "@tanstack/router-e2e-utils": "workspace:^",
+    "@tanstack/router-e2e-utils": "workspace:*",
     "@types/node": "^22.10.2",
     "autoprefixer": "^10.4.20",
     "postcss": "^8.5.1",
+    "srvx": "^0.8.6",
     "tailwindcss": "^3.4.17",
     "typescript": "^5.7.2",
+    "vite": "^7.1.7",
     "vite-plugin-solid": "^2.11.8",
     "vite-tsconfig-paths": "^5.1.4"
   }

Update script:

-    "start": "pnpx srvx --prod -s ../client dist/server/server.js",
+    "start": "srvx --prod -s ../client dist/server/server.js",
e2e/solid-start/basic-solid-query/tests/app.spec.ts (1)

7-7: Consider using complete text or data-testid for more stable test selectors.

The link text "sunt aut facere repe" appears truncated mid-word, which could make the test fragile if the display text changes slightly. Consider using the complete text or a data-testid attribute for more reliable element selection.

e2e/solid-start/query-integration/src/queryOptions.ts (1)

6-11: Optionally support AbortSignal to avoid dangling timers on cancellations.

Not required for e2e, but cheap to add for best practice.

-    queryFn: async () => {
+    queryFn: async ({ signal }) => {
       console.log('fetching query data')
-      await new Promise<void>((resolve) => {
-        setTimeout(resolve, 500)
-      })
+      await new Promise<void>((resolve, reject) => {
+        const id = setTimeout(resolve, 500)
+        signal?.addEventListener('abort', () => {
+          clearTimeout(id)
+          reject(new DOMException('Aborted', 'AbortError'))
+        })
+      })
e2e/solid-start/query-integration/src/routes/loader-fetchQuery/$type.tsx (1)

3-15: Tighten typings: zod import + loader return type (avoid as any).

  • Use named import for zod to avoid relying on synthetic default imports.
  • Let the loader return string | undefined and drop the cast.
-import z from 'zod'
+import { z } from 'zod'
@@
-export const Route = createFileRoute('/loader-fetchQuery/$type')({
+export const Route = createFileRoute('/loader-fetchQuery/$type')({
@@
-  loader: async ({ context, params }) => {
+  // Loader returns the string for 'sync', otherwise undefined
+  loader: async ({ context, params }): Promise<string | undefined> => {
     await context.queryClient.ensureQueryData(context.queryOptions)
     if (params.type === 'sync') {
       return context.queryClient.getQueryData(
         context.queryOptions.queryKey,
       ) as string
     }
-    return undefined as any
+    return undefined
   },
 })
@@
-  const query = useQuery(() => {
-    return makeQueryOptions(`loader-fetchQuery-${params().type}`)
-  })
+  const query = useQuery(() =>
+    makeQueryOptions(`loader-fetchQuery-${params().type}`),
+  )

Also applies to: 19-27, 33-35

e2e/solid-start/basic-solid-query/src/routes/users.tsx (1)

20-25: Optional: avoid rebuilding the array each render.

Not a blocker, but you can memoize the list or render the “Non-existent User” as a separate item.

-import { For } from 'solid-js'
+import { For, createMemo } from 'solid-js'
@@
 function UsersComponent() {
   const usersQuery = useQuery(() => usersQueryOptions())
+  const users = createMemo(() => usersQuery.data ?? [])
@@
-        <For
-          each={[
-            ...(usersQuery.data ?? []),
-            { id: 'i-do-not-exist', name: 'Non-existent User', email: '' },
-          ]}
-        >
+        <For each={users()}>
           {(user) => (
             <li class="whitespace-nowrap">
@@
           )}
         </For>
+        <li class="whitespace-nowrap">
+          <Link
+            to="/users/$userId"
+            params={{ userId: 'i-do-not-exist' }}
+            class="block py-1 text-blue-800 hover:text-blue-600"
+            activeProps={{ class: 'text-black font-bold' }}
+          >
+            <div>Non-existent User</div>
+          </Link>
+        </li>
e2e/solid-start/basic-solid-query/src/routes/__root.tsx (3)

78-78: Add lang attribute for accessibility.

Helps screen readers and SEO.

-    <html>
+    <html lang="en">

28-33: Open Graph tags should use "property", not "name".

seo() returns og:* entries with name; prefer property for OG crawlers.

Apply in src/utils/seo.ts:

-    { name: 'og:type', content: 'website' },
-    { name: 'og:title', content: title },
-    { name: 'og:description', content: description },
+    { property: 'og:type', content: 'website' },
+    { property: 'og:title', content: title },
+    { property: 'og:description', content: description },
@@
-          { name: 'og:image', content: image },
+          { property: 'og:image', content: image },

9-9: Optional: import the stable alias for devtools.

Prefer TanStackRouterDevtools for consistency with examples.

-import { TanStackRouterDevtoolsInProd } from '@tanstack/solid-router-devtools'
+import { TanStackRouterDevtools } from '@tanstack/solid-router-devtools'
@@
-        <TanStackRouterDevtoolsInProd position="bottom-right" />
+        <TanStackRouterDevtools position="bottom-right" />
packages/solid-router-ssr-query/src/index.tsx (1)

12-31: Make wrapper idempotent and document options.

Repeated setup currently nests providers. Add a one-time guard and brief JSDoc.

+/**
+ * Wire up SSR integration between Solid Router and Solid Query.
+ *
+ * By default, wraps the router's Wrap with a QueryClientProvider.
+ * Set `wrapQueryClient` to `false` to opt out.
+ */
 export function setupRouterSsrQueryIntegration<TRouter extends AnyRouter>(
   opts: Options<TRouter>,
 ) {
   setupCoreRouterSsrQueryIntegration(opts)
 
-  if (opts.wrapQueryClient === false) {
+  // Prevent double-wrapping if called more than once
+  const WRAPPED = Symbol.for('@tanstack/solid-router-ssr-query:wrapped')
+  if ((opts.router as any)[WRAPPED]) {
+    return
+  }
+
+  if (opts.wrapQueryClient === false) {
     return
   }
 
   const OGWrap =
     opts.router.options.Wrap ||
     ((props: { children: JSX.Element }) => props.children)
 
   opts.router.options.Wrap = (props) => {
     return (
       <QueryClientProvider client={opts.queryClient}>
         <OGWrap>{props.children}</OGWrap>
       </QueryClientProvider>
     )
   }
+  ;(opts.router as any)[WRAPPED] = true
 }
e2e/solid-start/basic-solid-query/src/routes/posts.tsx (1)

31-33: Ensure route param is a string.

Route params are strings; coerce numeric ids to avoid TS/narrowing issues.

-                  params={{
-                    postId: post.id,
-                  }}
+                  params={{ postId: String(post.id) }}
e2e/solid-start/query-integration/playwright.config.ts (1)

23-28: Make webServer command cross‑platform.

Env var syntax and quoted values break on Windows. Use cross-env (or Playwright env option).

-    command: `VITE_NODE_ENV="test" VITE_EXTERNAL_PORT=${EXTERNAL_PORT} VITE_SERVER_PORT=${PORT} pnpm build && VITE_NODE_ENV="test" VITE_EXTERNAL_PORT=${EXTERNAL_PORT} PORT=${PORT} VITE_SERVER_PORT=${PORT} pnpm start`,
+    command: `cross-env VITE_NODE_ENV=test VITE_EXTERNAL_PORT=${EXTERNAL_PORT} VITE_SERVER_PORT=${PORT} pnpm build && cross-env VITE_NODE_ENV=test VITE_EXTERNAL_PORT=${EXTERNAL_PORT} PORT=${PORT} VITE_SERVER_PORT=${PORT} pnpm start`,

Alternatively, set webServer.env and simplify the command.

e2e/solid-start/query-integration/src/routes/__root.tsx (2)

28-28: Add lang attribute on html.

Improves a11y and SEO.

-    <html>
+    <html lang="en">

15-22: Optional: add viewport meta.

Consistent with the other root; helps responsive behavior.

   head: () => ({
     meta: [
       {
         charset: 'utf-8',
       },
+      { name: 'viewport', content: 'width=device-width, initial-scale=1' },
     ],
packages/solid-router-ssr-query/package.json (1)

71-79: Align dev vs peer version ranges for Solid Query.

Use the same minimum to avoid subtle type divergence.

-    "@tanstack/solid-query": ">=5.66.0",
+    "@tanstack/solid-query": ">=5.66.2",
e2e/solid-start/basic-solid-query/src/utils/users.tsx (1)

15-25: Optional: set a short staleTime to reduce e2e flakiness.

 export const usersQueryOptions = () =>
   queryOptions({
     queryKey: ['users'],
+    staleTime: 5_000,
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7ba07e3 and 197bd86.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (51)
  • e2e/solid-start/basic-solid-query/package.json (1 hunks)
  • e2e/solid-start/basic-solid-query/playwright.config.ts (1 hunks)
  • e2e/solid-start/basic-solid-query/postcss.config.mjs (1 hunks)
  • e2e/solid-start/basic-solid-query/src/components/DefaultCatchBoundary.tsx (1 hunks)
  • e2e/solid-start/basic-solid-query/src/components/NotFound.tsx (1 hunks)
  • e2e/solid-start/basic-solid-query/src/routeTree.gen.ts (1 hunks)
  • e2e/solid-start/basic-solid-query/src/router.tsx (1 hunks)
  • e2e/solid-start/basic-solid-query/src/routes/__root.tsx (1 hunks)
  • e2e/solid-start/basic-solid-query/src/routes/api.users.ts (1 hunks)
  • e2e/solid-start/basic-solid-query/src/routes/api/users.$id.ts (1 hunks)
  • e2e/solid-start/basic-solid-query/src/routes/deferred.tsx (1 hunks)
  • e2e/solid-start/basic-solid-query/src/routes/index.tsx (1 hunks)
  • e2e/solid-start/basic-solid-query/src/routes/posts.$postId.tsx (1 hunks)
  • e2e/solid-start/basic-solid-query/src/routes/posts.index.tsx (1 hunks)
  • e2e/solid-start/basic-solid-query/src/routes/posts.tsx (1 hunks)
  • e2e/solid-start/basic-solid-query/src/routes/posts_.$postId.deep.tsx (1 hunks)
  • e2e/solid-start/basic-solid-query/src/routes/users.$userId.tsx (1 hunks)
  • e2e/solid-start/basic-solid-query/src/routes/users.index.tsx (1 hunks)
  • e2e/solid-start/basic-solid-query/src/routes/users.tsx (1 hunks)
  • e2e/solid-start/basic-solid-query/src/styles/app.css (1 hunks)
  • e2e/solid-start/basic-solid-query/src/utils/posts.tsx (1 hunks)
  • e2e/solid-start/basic-solid-query/src/utils/seo.ts (1 hunks)
  • e2e/solid-start/basic-solid-query/src/utils/users.tsx (1 hunks)
  • e2e/solid-start/basic-solid-query/tailwind.config.mjs (1 hunks)
  • e2e/solid-start/basic-solid-query/tests/app.spec.ts (1 hunks)
  • e2e/solid-start/basic-solid-query/tests/setup/global.setup.ts (1 hunks)
  • e2e/solid-start/basic-solid-query/tests/setup/global.teardown.ts (1 hunks)
  • e2e/solid-start/basic-solid-query/tsconfig.json (1 hunks)
  • e2e/solid-start/basic-solid-query/vite.config.ts (1 hunks)
  • e2e/solid-start/query-integration/package.json (1 hunks)
  • e2e/solid-start/query-integration/playwright.config.ts (1 hunks)
  • e2e/solid-start/query-integration/postcss.config.mjs (1 hunks)
  • e2e/solid-start/query-integration/src/queryOptions.ts (1 hunks)
  • e2e/solid-start/query-integration/src/routeTree.gen.ts (1 hunks)
  • e2e/solid-start/query-integration/src/router.tsx (1 hunks)
  • e2e/solid-start/query-integration/src/routes/__root.tsx (1 hunks)
  • e2e/solid-start/query-integration/src/routes/index.tsx (1 hunks)
  • e2e/solid-start/query-integration/src/routes/loader-fetchQuery/$type.tsx (1 hunks)
  • e2e/solid-start/query-integration/src/routes/useQuery.tsx (1 hunks)
  • e2e/solid-start/query-integration/src/styles/app.css (1 hunks)
  • e2e/solid-start/query-integration/tailwind.config.mjs (1 hunks)
  • e2e/solid-start/query-integration/tests/app.spec.ts (1 hunks)
  • e2e/solid-start/query-integration/tsconfig.json (1 hunks)
  • e2e/solid-start/query-integration/vite.config.ts (1 hunks)
  • package.json (1 hunks)
  • packages/solid-router-ssr-query/README.md (1 hunks)
  • packages/solid-router-ssr-query/eslint.config.js (1 hunks)
  • packages/solid-router-ssr-query/package.json (1 hunks)
  • packages/solid-router-ssr-query/src/index.tsx (1 hunks)
  • packages/solid-router-ssr-query/tsconfig.json (1 hunks)
  • packages/solid-router-ssr-query/vite.config.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use TypeScript in strict mode with extensive type safety across the codebase

Files:

  • e2e/solid-start/query-integration/src/router.tsx
  • e2e/solid-start/basic-solid-query/src/components/DefaultCatchBoundary.tsx
  • e2e/solid-start/basic-solid-query/src/routes/users.index.tsx
  • e2e/solid-start/basic-solid-query/src/components/NotFound.tsx
  • e2e/solid-start/basic-solid-query/src/utils/posts.tsx
  • e2e/solid-start/basic-solid-query/src/routes/posts_.$postId.deep.tsx
  • e2e/solid-start/query-integration/src/routes/loader-fetchQuery/$type.tsx
  • e2e/solid-start/basic-solid-query/src/utils/seo.ts
  • e2e/solid-start/basic-solid-query/src/routes/posts.index.tsx
  • e2e/solid-start/basic-solid-query/src/routes/posts.$postId.tsx
  • e2e/solid-start/basic-solid-query/src/routes/deferred.tsx
  • e2e/solid-start/basic-solid-query/src/routes/api.users.ts
  • e2e/solid-start/basic-solid-query/src/routes/users.tsx
  • e2e/solid-start/query-integration/src/queryOptions.ts
  • e2e/solid-start/basic-solid-query/src/router.tsx
  • e2e/solid-start/basic-solid-query/tests/setup/global.setup.ts
  • e2e/solid-start/query-integration/src/routes/index.tsx
  • e2e/solid-start/query-integration/src/routes/useQuery.tsx
  • e2e/solid-start/basic-solid-query/src/routes/api/users.$id.ts
  • e2e/solid-start/basic-solid-query/src/routes/__root.tsx
  • e2e/solid-start/query-integration/tests/app.spec.ts
  • e2e/solid-start/basic-solid-query/src/routes/index.tsx
  • e2e/solid-start/query-integration/src/routes/__root.tsx
  • packages/solid-router-ssr-query/vite.config.ts
  • e2e/solid-start/basic-solid-query/src/utils/users.tsx
  • e2e/solid-start/basic-solid-query/src/routes/users.$userId.tsx
  • e2e/solid-start/basic-solid-query/src/routes/posts.tsx
  • e2e/solid-start/basic-solid-query/tests/setup/global.teardown.ts
  • e2e/solid-start/query-integration/src/routeTree.gen.ts
  • e2e/solid-start/query-integration/playwright.config.ts
  • e2e/solid-start/query-integration/vite.config.ts
  • e2e/solid-start/basic-solid-query/playwright.config.ts
  • packages/solid-router-ssr-query/src/index.tsx
  • e2e/solid-start/basic-solid-query/tests/app.spec.ts
  • e2e/solid-start/basic-solid-query/src/routeTree.gen.ts
  • e2e/solid-start/basic-solid-query/vite.config.ts
e2e/**

📄 CodeRabbit inference engine (AGENTS.md)

Store end-to-end tests under the e2e/ directory

Files:

  • e2e/solid-start/query-integration/src/router.tsx
  • e2e/solid-start/basic-solid-query/postcss.config.mjs
  • e2e/solid-start/basic-solid-query/src/components/DefaultCatchBoundary.tsx
  • e2e/solid-start/basic-solid-query/src/routes/users.index.tsx
  • e2e/solid-start/basic-solid-query/src/components/NotFound.tsx
  • e2e/solid-start/basic-solid-query/tailwind.config.mjs
  • e2e/solid-start/basic-solid-query/src/utils/posts.tsx
  • e2e/solid-start/basic-solid-query/src/routes/posts_.$postId.deep.tsx
  • e2e/solid-start/query-integration/src/routes/loader-fetchQuery/$type.tsx
  • e2e/solid-start/basic-solid-query/src/utils/seo.ts
  • e2e/solid-start/basic-solid-query/src/routes/posts.index.tsx
  • e2e/solid-start/basic-solid-query/src/routes/posts.$postId.tsx
  • e2e/solid-start/basic-solid-query/src/routes/deferred.tsx
  • e2e/solid-start/basic-solid-query/src/styles/app.css
  • e2e/solid-start/basic-solid-query/src/routes/api.users.ts
  • e2e/solid-start/basic-solid-query/src/routes/users.tsx
  • e2e/solid-start/query-integration/src/styles/app.css
  • e2e/solid-start/query-integration/src/queryOptions.ts
  • e2e/solid-start/basic-solid-query/src/router.tsx
  • e2e/solid-start/basic-solid-query/tests/setup/global.setup.ts
  • e2e/solid-start/query-integration/src/routes/index.tsx
  • e2e/solid-start/query-integration/src/routes/useQuery.tsx
  • e2e/solid-start/query-integration/postcss.config.mjs
  • e2e/solid-start/basic-solid-query/src/routes/api/users.$id.ts
  • e2e/solid-start/basic-solid-query/src/routes/__root.tsx
  • e2e/solid-start/query-integration/tests/app.spec.ts
  • e2e/solid-start/basic-solid-query/src/routes/index.tsx
  • e2e/solid-start/query-integration/src/routes/__root.tsx
  • e2e/solid-start/basic-solid-query/tsconfig.json
  • e2e/solid-start/basic-solid-query/src/utils/users.tsx
  • e2e/solid-start/basic-solid-query/src/routes/users.$userId.tsx
  • e2e/solid-start/basic-solid-query/src/routes/posts.tsx
  • e2e/solid-start/basic-solid-query/tests/setup/global.teardown.ts
  • e2e/solid-start/query-integration/src/routeTree.gen.ts
  • e2e/solid-start/query-integration/tsconfig.json
  • e2e/solid-start/query-integration/playwright.config.ts
  • e2e/solid-start/query-integration/tailwind.config.mjs
  • e2e/solid-start/query-integration/vite.config.ts
  • e2e/solid-start/basic-solid-query/playwright.config.ts
  • e2e/solid-start/query-integration/package.json
  • e2e/solid-start/basic-solid-query/tests/app.spec.ts
  • e2e/solid-start/basic-solid-query/src/routeTree.gen.ts
  • e2e/solid-start/basic-solid-query/package.json
  • e2e/solid-start/basic-solid-query/vite.config.ts
**/src/routes/**

📄 CodeRabbit inference engine (AGENTS.md)

Place file-based routes under src/routes/ directories

Files:

  • e2e/solid-start/basic-solid-query/src/routes/users.index.tsx
  • e2e/solid-start/basic-solid-query/src/routes/posts_.$postId.deep.tsx
  • e2e/solid-start/query-integration/src/routes/loader-fetchQuery/$type.tsx
  • e2e/solid-start/basic-solid-query/src/routes/posts.index.tsx
  • e2e/solid-start/basic-solid-query/src/routes/posts.$postId.tsx
  • e2e/solid-start/basic-solid-query/src/routes/deferred.tsx
  • e2e/solid-start/basic-solid-query/src/routes/api.users.ts
  • e2e/solid-start/basic-solid-query/src/routes/users.tsx
  • e2e/solid-start/query-integration/src/routes/index.tsx
  • e2e/solid-start/query-integration/src/routes/useQuery.tsx
  • e2e/solid-start/basic-solid-query/src/routes/api/users.$id.ts
  • e2e/solid-start/basic-solid-query/src/routes/__root.tsx
  • e2e/solid-start/basic-solid-query/src/routes/index.tsx
  • e2e/solid-start/query-integration/src/routes/__root.tsx
  • e2e/solid-start/basic-solid-query/src/routes/users.$userId.tsx
  • e2e/solid-start/basic-solid-query/src/routes/posts.tsx
**/package.json

📄 CodeRabbit inference engine (AGENTS.md)

Use workspace:* protocol for internal dependencies in package.json files

Files:

  • package.json
  • packages/solid-router-ssr-query/package.json
  • e2e/solid-start/query-integration/package.json
  • e2e/solid-start/basic-solid-query/package.json
🧠 Learnings (2)
📚 Learning: 2025-09-23T17:36:12.598Z
Learnt from: CR
PR: TanStack/router#0
File: AGENTS.md:0-0
Timestamp: 2025-09-23T17:36:12.598Z
Learning: Applies to **/*.{ts,tsx} : Use TypeScript in strict mode with extensive type safety across the codebase

Applied to files:

  • e2e/solid-start/basic-solid-query/tsconfig.json
📚 Learning: 2025-10-01T18:31:35.420Z
Learnt from: schiller-manuel
PR: TanStack/router#5330
File: e2e/react-start/custom-basepath/src/routeTree.gen.ts:58-61
Timestamp: 2025-10-01T18:31:35.420Z
Learning: Do not review files named `routeTree.gen.ts` in TanStack Router repositories, as these are autogenerated files that should not be manually modified.

Applied to files:

  • e2e/solid-start/query-integration/src/routeTree.gen.ts
🧬 Code graph analysis (28)
e2e/solid-start/query-integration/src/router.tsx (2)
e2e/solid-start/basic-solid-query/src/router.tsx (1)
  • getRouter (8-30)
packages/solid-router-ssr-query/src/index.tsx (1)
  • setupRouterSsrQueryIntegration (12-32)
e2e/solid-start/basic-solid-query/src/components/DefaultCatchBoundary.tsx (1)
examples/solid/start-basic/src/components/DefaultCatchBoundary.tsx (1)
  • DefaultCatchBoundary (10-53)
e2e/solid-start/basic-solid-query/src/routes/users.index.tsx (2)
e2e/solid-start/basic-solid-query/src/routes/users.$userId.tsx (1)
  • Route (8-17)
e2e/solid-start/basic-solid-query/src/routes/users.tsx (1)
  • Route (7-12)
e2e/solid-start/basic-solid-query/src/components/NotFound.tsx (2)
examples/solid/start-basic/src/components/NotFound.tsx (1)
  • NotFound (3-25)
e2e/solid-start/server-routes/src/components/NotFound.tsx (1)
  • NotFound (3-25)
e2e/solid-start/basic-solid-query/src/routes/posts_.$postId.deep.tsx (4)
e2e/solid-start/basic-solid-query/src/routes/__root.tsx (1)
  • Route (16-66)
e2e/solid-start/basic-solid-query/src/routes/posts.$postId.tsx (2)
  • Route (5-11)
  • PostErrorComponent (13-15)
e2e/solid-start/basic-solid-query/src/routes/posts.tsx (1)
  • Route (6-12)
e2e/solid-start/basic-solid-query/src/utils/posts.tsx (1)
  • postQueryOptions (22-33)
e2e/solid-start/query-integration/src/routes/loader-fetchQuery/$type.tsx (1)
e2e/solid-start/query-integration/src/queryOptions.ts (1)
  • makeQueryOptions (3-16)
e2e/solid-start/basic-solid-query/src/utils/seo.ts (1)
examples/solid/start-basic/src/utils/seo.ts (1)
  • title (1-33)
e2e/solid-start/basic-solid-query/src/routes/posts.index.tsx (3)
e2e/solid-start/basic-solid-query/src/routes/posts.$postId.tsx (1)
  • Route (5-11)
e2e/solid-start/basic-solid-query/src/routes/posts.tsx (1)
  • Route (6-12)
e2e/solid-start/basic-solid-query/src/routes/users.index.tsx (1)
  • Route (3-5)
e2e/solid-start/basic-solid-query/src/routes/posts.$postId.tsx (4)
e2e/solid-start/basic-solid-query/src/routes/__root.tsx (1)
  • Route (16-66)
e2e/solid-start/basic-solid-query/src/routes/posts.tsx (1)
  • Route (6-12)
e2e/solid-start/basic-solid-query/src/routes/posts_.$postId.deep.tsx (1)
  • Route (6-21)
e2e/solid-start/basic-solid-query/src/utils/posts.tsx (1)
  • postQueryOptions (22-33)
e2e/solid-start/basic-solid-query/src/routes/deferred.tsx (2)
e2e/solid-start/basic-solid-query/src/routes/__root.tsx (1)
  • Route (16-66)
e2e/solid-start/basic-solid-query/src/routes/posts.tsx (1)
  • Route (6-12)
e2e/solid-start/basic-solid-query/src/routes/api.users.ts (2)
e2e/solid-start/basic-solid-query/src/routes/api/users.$id.ts (1)
  • Route (12-31)
e2e/solid-start/basic-solid-query/src/utils/users.tsx (1)
  • User (4-8)
e2e/solid-start/basic-solid-query/src/routes/users.tsx (5)
e2e/solid-start/basic-solid-query/src/routes/__root.tsx (1)
  • Route (16-66)
e2e/solid-start/basic-solid-query/src/routes/api.users.ts (1)
  • Route (12-25)
e2e/solid-start/basic-solid-query/src/routes/api/users.$id.ts (1)
  • Route (12-31)
e2e/solid-start/basic-solid-query/src/routes/users.$userId.tsx (1)
  • Route (8-17)
e2e/solid-start/basic-solid-query/src/utils/users.tsx (1)
  • usersQueryOptions (15-25)
e2e/solid-start/basic-solid-query/src/router.tsx (4)
e2e/solid-start/query-integration/src/router.tsx (1)
  • getRouter (6-26)
e2e/solid-start/basic-solid-query/src/components/DefaultCatchBoundary.tsx (1)
  • DefaultCatchBoundary (6-8)
e2e/solid-start/basic-solid-query/src/components/NotFound.tsx (1)
  • NotFound (4-26)
packages/solid-router-ssr-query/src/index.tsx (1)
  • setupRouterSsrQueryIntegration (12-32)
e2e/solid-start/basic-solid-query/tests/setup/global.setup.ts (3)
scripts/set-ts-version.js (1)
  • packageJson (33-33)
e2e/solid-router/basic-solid-query-file-based/tests/setup/global.setup.ts (1)
  • setup (4-6)
e2e/solid-router/basic-solid-query/tests/setup/global.setup.ts (1)
  • setup (4-6)
e2e/solid-start/query-integration/src/routes/index.tsx (3)
e2e/solid-start/basic-solid-query/src/routes/index.tsx (1)
  • Route (3-5)
e2e/solid-start/query-integration/src/routes/__root.tsx (1)
  • Route (12-24)
e2e/solid-start/query-integration/src/routes/useQuery.tsx (1)
  • Route (7-12)
e2e/solid-start/query-integration/src/routes/useQuery.tsx (3)
e2e/solid-start/query-integration/src/queryOptions.ts (1)
  • makeQueryOptions (3-16)
e2e/solid-start/query-integration/src/routes/__root.tsx (1)
  • Route (12-24)
e2e/solid-start/query-integration/src/routes/loader-fetchQuery/$type.tsx (1)
  • Route (6-28)
e2e/solid-start/basic-solid-query/src/routes/api/users.$id.ts (2)
e2e/solid-start/basic-solid-query/src/routes/api.users.ts (1)
  • Route (12-25)
e2e/solid-start/basic-solid-query/src/utils/users.tsx (1)
  • User (4-8)
e2e/solid-start/basic-solid-query/src/routes/__root.tsx (6)
e2e/solid-start/query-integration/src/routes/__root.tsx (1)
  • Route (12-24)
e2e/solid-start/basic-solid-query/src/utils/seo.ts (1)
  • seo (1-30)
e2e/solid-start/basic-solid-query/src/components/DefaultCatchBoundary.tsx (1)
  • DefaultCatchBoundary (6-8)
e2e/solid-start/basic-solid-query/src/components/NotFound.tsx (1)
  • NotFound (4-26)
packages/router-devtools/src/index.tsx (1)
  • TanStackRouterDevtoolsInProd (5-5)
examples/solid/basic-solid-query-file-based/src/routes/__root.tsx (1)
  • RootComponent (25-71)
e2e/solid-start/basic-solid-query/src/routes/index.tsx (2)
e2e/solid-start/basic-solid-query/src/routes/__root.tsx (1)
  • Route (16-66)
e2e/solid-start/query-integration/src/routes/index.tsx (1)
  • Route (3-5)
e2e/solid-start/query-integration/src/routes/__root.tsx (3)
e2e/solid-start/basic-solid-query/src/routes/__root.tsx (1)
  • Route (16-66)
packages/router-devtools/src/index.tsx (1)
  • TanStackRouterDevtoolsInProd (5-5)
examples/solid/start-basic/src/routes/__root.tsx (1)
  • RootDocument (59-121)
packages/solid-router-ssr-query/vite.config.ts (1)
scripts/set-ts-version.js (1)
  • packageJson (33-33)
e2e/solid-start/basic-solid-query/src/routes/users.$userId.tsx (3)
e2e/solid-start/basic-solid-query/src/routes/api/users.$id.ts (1)
  • Route (12-31)
e2e/solid-start/basic-solid-query/src/utils/users.tsx (1)
  • userQueryOptions (27-37)
e2e/solid-start/basic-solid-query/src/components/NotFound.tsx (1)
  • NotFound (4-26)
e2e/solid-start/basic-solid-query/src/routes/posts.tsx (3)
e2e/solid-start/basic-solid-query/src/routes/__root.tsx (1)
  • Route (16-66)
e2e/solid-start/basic-solid-query/src/routes/posts.$postId.tsx (1)
  • Route (5-11)
e2e/solid-start/basic-solid-query/src/utils/posts.tsx (1)
  • postsQueryOptions (10-20)
e2e/solid-start/basic-solid-query/tests/setup/global.teardown.ts (7)
e2e/solid-router/basic-solid-query-file-based/tests/setup/global.teardown.ts (1)
  • teardown (4-6)
e2e/solid-router/basic-solid-query/tests/setup/global.teardown.ts (1)
  • teardown (4-6)
e2e/solid-router/basic-file-based/tests/setup/global.teardown.ts (1)
  • teardown (4-6)
e2e/solid-router/basic-file-based-code-splitting/tests/setup/global.teardown.ts (1)
  • teardown (4-6)
e2e/solid-router/basic-virtual-named-export-config-file-based/tests/setup/global.teardown.ts (1)
  • teardown (4-6)
e2e/solid-start/basic/tests/setup/global.teardown.ts (1)
  • teardown (4-6)
e2e/solid-router/basic-virtual-file-based/tests/setup/global.teardown.ts (1)
  • teardown (4-6)
e2e/solid-start/query-integration/src/routeTree.gen.ts (1)
e2e/solid-start/query-integration/src/router.tsx (1)
  • getRouter (6-26)
e2e/solid-start/basic-solid-query/playwright.config.ts (1)
scripts/set-ts-version.js (1)
  • packageJson (33-33)
packages/solid-router-ssr-query/src/index.tsx (1)
packages/router-ssr-query-core/src/index.ts (2)
  • RouterSsrQueryOptions (12-23)
  • setupCoreRouterSsrQueryIntegration (30-160)
e2e/solid-start/basic-solid-query/src/routeTree.gen.ts (1)
e2e/solid-start/basic-solid-query/src/router.tsx (1)
  • getRouter (8-30)
🪛 ESLint
e2e/solid-start/basic-solid-query/src/components/DefaultCatchBoundary.tsx

[error] 3-3: Prefer using a top-level type-only import instead of inline type specifiers.

(import/consistent-type-specifier-style)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Test
  • GitHub Check: Preview
🔇 Additional comments (39)
e2e/solid-start/basic-solid-query/tsconfig.json (1)

1-24: Configuration looks solid—well-aligned with TypeScript and SolidJS best practices.

This tsconfig correctly sets up strict mode with extensive type safety (per coding guidelines), SolidJS JSX support (jsxImportSource, jsx: "preserve"), and Vite-compatible module resolution (moduleResolution: "Bundler", noEmit). The path alias pattern (~/*./src/*) is idiomatic and will support clean imports in the test project. The ES2022 target and DOM library support are appropriate for a modern SSR setup.

e2e/solid-start/basic-solid-query/src/routes/posts_.$postId.deep.tsx (4)

1-4: LGTM!

All imports are appropriately used throughout the file.


6-6: Verify the underscore in the route path.

The route path /posts_/$postId/deep uses an underscore, creating a separate top-level segment rather than nesting under /posts. The sibling route at posts.$postId.tsx uses /posts/$postId without an underscore. If this route should be nested under the posts section, the path should be /posts/$postId/deep instead.

If the underscore is intentional (e.g., testing edge cases with underscores in paths), this is fine. Otherwise, consider this fix:

-export const Route = createFileRoute('/posts_/$postId/deep')({
+export const Route = createFileRoute('/posts/$postId/deep')({

Note: You would also need to rename the file from posts_.$postId.deep.tsx to posts.$postId.deep.tsx.


7-20: LGTM!

The loader, head, and error handling configuration follow the correct SSR patterns for TanStack Router and Solid Query integration. The data is properly ensured on the server, and the title is correctly passed to the head meta for SEO.


23-36: LGTM!

The component correctly implements the SSR + client-side hydration pattern:

  • Uses reactive params accessor correctly for Solid
  • Query factory function ensures reactivity when params change
  • Optional chaining provides safe access to query data
  • Data is prefetched in the loader, so the component picks up cached data without a waterfall
package.json (1)

99-99: LGTM!

The workspace override for @tanstack/solid-router-ssr-query correctly follows the established pattern and uses the workspace:* protocol as required by coding guidelines.

e2e/solid-start/query-integration/src/styles/app.css (1)

1-8: LGTM!

Standard Tailwind CSS setup with appropriate base styling. The configuration aligns with the PostCSS and Tailwind configs in the project.

e2e/solid-start/query-integration/postcss.config.mjs (1)

1-6: LGTM!

Standard PostCSS configuration for Tailwind CSS processing with autoprefixer. The setup is correct and aligns with the Tailwind configuration in the project.

e2e/solid-start/basic-solid-query/postcss.config.mjs (1)

1-6: LGTM!

Standard PostCSS configuration for Tailwind CSS processing. The setup is appropriate for this independent e2e test project.

e2e/solid-start/query-integration/tsconfig.json (1)

1-24: LGTM!

The TypeScript configuration is well-structured with strict mode enabled (as required by coding guidelines), appropriate Solid.js settings, and standard Vite/ESNext module resolution. The path alias and compiler options are correctly configured for the e2e test environment.

e2e/solid-start/basic-solid-query/src/components/DefaultCatchBoundary.tsx (1)

6-8: LGTM!

The component correctly wraps and forwards props to the ErrorComponent from @tanstack/solid-router. This simplified implementation is appropriate for the e2e test scenario.

e2e/solid-start/basic-solid-query/vite.config.ts (1)

1-14: LGTM!

The Vite configuration correctly wires up the SSR-enabled Solid Start plugin stack. The plugins are properly ordered with TypeScript path resolution, TanStack Start plugin, and Solid plugin with SSR enabled. This setup is appropriate for the e2e Solid Start scenario.

e2e/solid-start/basic-solid-query/tailwind.config.mjs (1)

1-8: LGTM

Minimal Tailwind config is fine for e2e. If you add MDX or external template paths later, remember to extend content globs.

e2e/solid-start/query-integration/tailwind.config.mjs (1)

1-8: LGTM

Matches the basic suite; no issues.

e2e/solid-start/basic-solid-query/src/styles/app.css (1)

1-8: LGTM!

Standard Tailwind CSS setup with appropriate directives and base body styling.

packages/solid-router-ssr-query/tsconfig.json (1)

1-8: LGTM!

TypeScript configuration correctly sets up Solid JSX support with appropriate compiler options and includes.

packages/solid-router-ssr-query/README.md (1)

1-38: LGTM!

Clear and concise documentation with appropriate installation instructions and usage example.

e2e/solid-start/basic-solid-query/tests/app.spec.ts (1)

12-18: LGTM!

User navigation test uses complete, stable text selectors and appropriate assertions.

e2e/solid-start/basic-solid-query/tests/setup/global.teardown.ts (1)

1-6: LGTM!

Standard teardown pattern consistent with other e2e projects in the monorepo.

e2e/solid-start/query-integration/tests/app.spec.ts (1)

1-34: LGTM!

Well-structured e2e tests with stable data-testid selectors and clear validation of SSR query streaming behavior for both synchronous and asynchronous scenarios.

e2e/solid-start/query-integration/src/routes/index.tsx (1)

1-13: LGTM!

Clean file-based route implementation with correct usage of TanStack Solid Router APIs.

e2e/solid-start/basic-solid-query/src/routes/index.tsx (1)

1-13: LGTM!

Clean file-based route implementation following the same pattern as other routes in the project.

e2e/solid-start/basic-solid-query/src/routes/posts.index.tsx (1)

1-9: LGTM!

The index route is correctly structured for the /posts/ path with a simple placeholder component. This follows the file-based routing pattern used elsewhere in the codebase.

e2e/solid-start/basic-solid-query/src/routes/users.index.tsx (1)

1-9: LGTM!

The index route is correctly structured for the /users/ path with a simple placeholder component, following the same pattern as the posts index route.

e2e/solid-start/query-integration/vite.config.ts (1)

1-14: LGTM!

The Vite configuration correctly wires TypeScript path resolution, TanStack Start integration, and Solid SSR support. The plugin order is appropriate with tsConfigPaths first to ensure path resolution works for subsequent plugins.

e2e/solid-start/basic-solid-query/tests/setup/global.setup.ts (1)

1-6: LGTM!

The global setup correctly initializes the dummy e2e server using the package name. Error handling is implicit through async/await propagation to the test runner, which is appropriate for test infrastructure.

e2e/solid-start/query-integration/src/router.tsx (1)

6-26: LGTM!

The router factory correctly configures the QueryClient with client-side-only experimental_prefetchInRender to avoid hydration mismatches, and properly integrates SSR query support. The setup follows the established pattern from related e2e projects.

e2e/solid-start/basic-solid-query/src/routes/deferred.tsx (2)

5-24: LGTM!

The deferred query implementation correctly demonstrates SSR query integration with:

  • Query prefetching in the loader to start fetching early
  • Proper Suspense boundary for loading states
  • Query options following TanStack Query patterns

26-54: LGTM!

The component structure is well-designed:

  • Suspense boundary with appropriate fallback
  • Local state (counter) demonstrates client-side interactivity during deferred loading
  • The DeferredQuery component correctly uses useQuery and handles the data display
  • Line 51's new Date() wrapper handles both Date objects and serialized date strings across SSR boundaries
e2e/solid-start/basic-solid-query/src/router.tsx (1)

8-30: LGTM!

The router factory is properly configured with:

  • Client-side-only experimental_prefetchInRender to prevent hydration mismatches
  • QueryClient context wiring for route loaders
  • Default error and not-found components for comprehensive error handling
  • SSR query integration setup

The implementation follows best practices and is consistent with the established patterns.

e2e/solid-start/basic-solid-query/playwright.config.ts (1)

1-39: LGTM!

The Playwright configuration is properly structured with:

  • Dynamic port allocation from e2e utilities
  • Global setup/teardown for test lifecycle management
  • Server reuse optimization for local development (line 29)
  • Single worker to avoid concurrency issues
  • Comprehensive webServer configuration with proper environment variables

The webServer command (line 27) is complex but functional, correctly setting up environment variables for both build and start phases.

e2e/solid-start/query-integration/src/routes/useQuery.tsx (1)

7-12: LGTM — loader prefetch + useQuery wiring is correct.

Prefetch ensures SSR/hydration consistency; static qOptions keeps keys stable.

Also applies to: 14-24

packages/solid-router-ssr-query/vite.config.ts (1)

4-4: No action needed—JSON import is properly supported.

The verification confirms resolveJsonModule: true is enabled across the project's TypeScript configuration. The JSON import at line 4 will work correctly at runtime without requiring createRequire.

packages/solid-router-ssr-query/eslint.config.js (1)

3-12: Based on the official documentation for eslint-plugin-solid, the TypeScript config is intended to be spread directly into a configuration object alongside other keys like files and languageOptions. This pattern indicates the preset exports a single configuration object, not an array.

The current code in the PR follows the documented usage pattern. While flat configs are also available as plugin.configs['flat/recommended'] and plugin.configs['flat/typescript'] after importing the plugin itself, the standard import from eslint-plugin-solid/configs/typescript behaves as shown in the official examples—as an object suitable for spreading.

The review comment is incorrect and adds unnecessary complexity.

The proposed normalization pattern assumes a potential but undocumented array export. The official documentation consistently demonstrates the object spread pattern used in the current PR code, which is the correct approach.

Likely an incorrect or invalid review comment.

e2e/solid-start/query-integration/playwright.config.ts (1)

6-6: Based on my verification:

No issues found — the JSON import attributes syntax is properly supported.

Playwright officially requires Node.js latest 20.x, 22.x or 24.x, and the with { type: 'json' } syntax is supported in Node.js since version 20.10. Your TypeScript config for e2e/solid-start/query-integration/ has resolveJsonModule: true and moduleResolution: "Bundler", which are properly configured for this syntax.

The code in the Playwright config is both TypeScript-compatible and Node.js-compatible with modern versions that your project likely targets.

e2e/solid-start/query-integration/src/routeTree.gen.ts (1)

1-104: Autogenerated file — skipping review.

Based on learnings

e2e/solid-start/basic-solid-query/src/routeTree.gen.ts (1)

1-304: Autogenerated file — skipping review.

Based on learnings

packages/solid-router-ssr-query/package.json (2)

45-55: Manual verification needed: Confirm the build outputs dist/cjs/index.d.cts.

The package references .d.cts in its exports for CJS types, which is consistent across the entire monorepo. However, because the actual build output depends on the external @tanstack/config/vite tool and the sandbox cannot execute builds, this requires verification by running:

npm run build
fd index.d.cts dist/cjs

Or by checking the published npm package to confirm .d.cts files are included.


63-65: Update Node engine to at least >=14.18.0, not >=18.

Based on the actual dependencies in the package.json:

  • vite-plugin-solid v2.11.8 requires Node >= 14.18.0
  • solid-js 1.9.x requires Node >= 8

The current "node": ">=12" is outdated and should be updated to "node": ">=14.18.0" to meet the vite-plugin-solid requirement. However, updating to >=18 as suggested exceeds what the dependencies require.

  "engines": {
-   "node": ">=12"
+   "node": ">=14.18.0"
  },

Likely an incorrect or invalid review comment.

Comment on lines +53 to +55
{ rel: 'manifest', href: '/site.webmanifest', color: '#fffff' },
{ rel: 'icon', href: '/favicon.ico' },
],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Remove invalid color attribute from manifest link.

does not support a color attribute. Use a meta name="theme-color" or mask-icon link if needed.
-      { rel: 'manifest', href: '/site.webmanifest', color: '#fffff' },
+      { rel: 'manifest', href: '/site.webmanifest' },
+      // Optional page color:
+      // { rel: 'mask-icon', href: '/safari-pinned-tab.svg', color: '#ffffff' },
+      // Or:
+      // { name: 'theme-color', content: '#ffffff' },
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
{ rel: 'manifest', href: '/site.webmanifest', color: '#fffff' },
{ rel: 'icon', href: '/favicon.ico' },
],
{ rel: 'manifest', href: '/site.webmanifest' },
// Optional page color:
// { rel: 'mask-icon', href: '/safari-pinned-tab.svg', color: '#ffffff' },
// Or:
// { name: 'theme-color', content: '#ffffff' },
{ rel: 'icon', href: '/favicon.ico' },
],
🤖 Prompt for AI Agents
In e2e/solid-start/basic-solid-query/src/routes/__root.tsx around lines 53 to
55, the manifest link entry includes an invalid color attribute; remove the
color property from the manifest link object and, if a theme color is required,
add a meta tag with name="theme-color" and the desired color (or use a mask-icon
link) in the document head instead.

Comment on lines +15 to +22
GET: async ({ request }) => {
console.info('Fetching users... @', request.url)
const res = await axios.get<Array<User>>(`${queryURL}/users`)
const list = res.data.slice(0, 10)
return json(
list.map((u) => ({ id: u.id, name: u.name, email: u.email })),
)
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Add error handling (and timeout) to avoid unhandled 500s from upstream failures.

The GET handler can throw on network errors. Wrap in try/catch and return a controlled error. Optional: set a timeout.

Apply:

       GET: async ({ request }) => {
         console.info('Fetching users... @', request.url)
-        const res = await axios.get<Array<User>>(`${queryURL}/users`)
-        const list = res.data.slice(0, 10)
-        return json(
-          list.map((u) => ({ id: u.id, name: u.name, email: u.email })),
-        )
+        try {
+          const res = await axios.get<Array<User>>(`${queryURL}/users`, {
+            timeout: 5000,
+          })
+          const list = res.data.slice(0, 10)
+          return json(
+            list.map((u) => ({ id: u.id, name: u.name, email: u.email })),
+          )
+        } catch (e) {
+          console.error('Failed to fetch users:', e)
+          return json({ error: 'Failed to fetch users' }, { status: 502 })
+        }
       },

Also confirm these envs are set in test runs:


🏁 Script executed:

#!/bin/bash
rg -nP "(VITE_NODE_ENV|VITE_EXTERNAL_PORT)" -S -g "e2e/**"

Length of output: 16936



🏁 Script executed:

#!/bin/bash
# Get the actual code at lines 15-22 of the file
sed -n '15,22p' e2e/solid-start/basic-solid-query/src/routes/api.users.ts

Length of output: 318


🏁 Script executed:

#!/bin/bash
# Get broader context around the handler to understand the complete function
sed -n '1,30p' e2e/solid-start/basic-solid-query/src/routes/api.users.ts

Length of output: 765


Add error handling to the GET handler to prevent unhandled 500s from network failures.

The code currently has no error handling for the axios call on line 17. Network errors will propagate as unhandled exceptions, returning 500 status. Wrap in try/catch, set a timeout, and return a controlled 502 error.

      GET: async ({ request }) => {
        console.info('Fetching users... @', request.url)
-        const res = await axios.get<Array<User>>(`${queryURL}/users`)
-        const list = res.data.slice(0, 10)
-        return json(
-          list.map((u) => ({ id: u.id, name: u.name, email: u.email })),
-        )
+        try {
+          const res = await axios.get<Array<User>>(`${queryURL}/users`, {
+            timeout: 5000,
+          })
+          const list = res.data.slice(0, 10)
+          return json(
+            list.map((u) => ({ id: u.id, name: u.name, email: u.email })),
+          )
+        } catch (e) {
+          console.error('Failed to fetch users:', e)
+          return json({ error: 'Failed to fetch users' }, { status: 502 })
+        }
       },

Environment variables VITE_NODE_ENV and VITE_EXTERNAL_PORT are confirmed configured in the test setup (e.e./solid-start/basic-solid-query/playwright.config.ts).

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
GET: async ({ request }) => {
console.info('Fetching users... @', request.url)
const res = await axios.get<Array<User>>(`${queryURL}/users`)
const list = res.data.slice(0, 10)
return json(
list.map((u) => ({ id: u.id, name: u.name, email: u.email })),
)
},
GET: async ({ request }) => {
console.info('Fetching users... @', request.url)
try {
const res = await axios.get<Array<User>>(`${queryURL}/users`, {
timeout: 5000,
})
const list = res.data.slice(0, 10)
return json(
list.map((u) => ({ id: u.id, name: u.name, email: u.email })),
)
} catch (e) {
console.error('Failed to fetch users:', e)
return json({ error: 'Failed to fetch users' }, { status: 502 })
}
},
🤖 Prompt for AI Agents
In e2e/solid-start/basic-solid-query/src/routes/api.users.ts around lines 15 to
22, the GET handler calls axios.get without error handling or a timeout which
lets network failures bubble up as unhandled 500s; wrap the axios call and
response mapping in a try/catch, add a timeout option to the axios request (e.g.
3–5s) and on catch log the error and return a controlled JSON response with an
appropriate error message and HTTP status 502 (using the existing json(...)
response helper with the status override).

Comment on lines +26 to +34
to="/posts/$postId/deep"
params={{
postId: postQuery.data?.id ?? '',
}}
activeProps={{ class: 'text-black font-bold' }}
class="inline-block py-1 text-blue-800 hover:text-blue-600"
>
Deep View
</Link>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Fix broken Link target; and avoid linking with empty postId.

The deep route file in this app is posts_.$postId.deep.tsx (path '/posts_/$postId/deep'), but this Link points to '/posts/$postId/deep'. Also, it renders with postId '' before data is ready.

Apply:

-      <Link
-        to="/posts/$postId/deep"
-        params={{
-          postId: postQuery.data?.id ?? '',
-        }}
-        activeProps={{ class: 'text-black font-bold' }}
-        class="inline-block py-1 text-blue-800 hover:text-blue-600"
-      >
-        Deep View
-      </Link>
+      {postQuery.data && (
+        <Link
+          to="/posts_/$postId/deep"
+          params={{ postId: String(postQuery.data.id) }}
+          activeProps={{ class: 'text-black font-bold' }}
+          class="inline-block py-1 text-blue-800 hover:text-blue-600"
+        >
+          Deep View
+        </Link>
+      )}

Confirm the intended route path in:

  • e2e/solid-start/basic-solid-query/src/routes/posts_.$postId.deep.tsx

🏁 Script executed:

#!/bin/bash
# Search for the deep route file mentioned in the review
find e2e/solid-start/basic-solid-query/src/routes -name "*deep*" -type f

Length of output: 68


🏁 Script executed:

#!/bin/bash
# List all route files in the posts directory to understand structure
fd -e tsx -e ts e2e/solid-start/basic-solid-query/src/routes | grep -i post | head -20

Length of output: 481


🏁 Script executed:

#!/bin/bash
# Check the actual file being reviewed for context on postQuery and Link
cat e2e/solid-start/basic-solid-query/src/routes/posts.\$postId.tsx | head -50

Length of output: 1142


🏁 Script executed:

#!/bin/bash
# Search for other references to the deep route to see if this is isolated
rg -n "posts.*deep" e2e/solid-start/basic-solid-query/src --type tsx --type ts

Length of output: 27


🏁 Script executed:

#!/bin/bash
# Check the deep route file to understand its structure
cat e2e/solid-start/basic-solid-query/src/routes/posts_.\$postId.deep.tsx

Length of output: 1098


Fix broken Link target path and prevent linking with missing postId.

The deep route is declared as /posts_/$postId/deep (with underscore in Solid Start file-based routing), but this Link points to /posts/$postId/deep. Additionally, the Link renders unconditionally with an empty postId when postQuery.data is undefined.

Apply:

-      <Link
-        to="/posts/$postId/deep"
-        params={{
-          postId: postQuery.data?.id ?? '',
-        }}
-        activeProps={{ class: 'text-black font-bold' }}
-        class="inline-block py-1 text-blue-800 hover:text-blue-600"
-      >
-        Deep View
-      </Link>
+      {postQuery.data && (
+        <Link
+          to="/posts_/$postId/deep"
+          params={{ postId: String(postQuery.data.id) }}
+          activeProps={{ class: 'text-black font-bold' }}
+          class="inline-block py-1 text-blue-800 hover:text-blue-600"
+        >
+          Deep View
+        </Link>
+      )}

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In e2e/solid-start/basic-solid-query/src/routes/posts.$postId.tsx around lines
26-34, the Link uses the wrong route path and can render with an empty postId;
change the to prop to "/posts_/$postId/deep" (matching the file-based route) and
prevent rendering/navigation when postId is missing by computing const postId =
postQuery.data?.id and either render the Link only when postId is truthy (e.g.,
{postId && <Link ... params={{ postId }} />}) or disable/omit the params and add
aria-disabled when postId is falsy so the Link never points to an empty id.

Comment on lines +9 to +11
loader: async ({ context, params: { userId } }) => {
await context.queryClient.ensureQueryData(userQueryOptions(userId))
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Map 404s to notFound() so notFoundComponent renders (ensure status is preserved).

Errors from ensureQueryData currently become route errors, not 404s. Wrap and throw notFound() on 404 to hit notFoundComponent.

-import { ErrorComponent, createFileRoute } from '@tanstack/solid-router'
+import { ErrorComponent, createFileRoute, notFound } from '@tanstack/solid-router'

 export const Route = createFileRoute('/users/$userId')({
   loader: async ({ context, params: { userId } }) => {
-    await context.queryClient.ensureQueryData(userQueryOptions(userId))
+    try {
+      await context.queryClient.ensureQueryData(userQueryOptions(userId))
+    } catch (e) {
+      const status = (e as any)?.response?.status ?? (e as any)?.status
+      if (status === 404) throw notFound()
+      throw e
+    }
   },
🤖 Prompt for AI Agents
In e2e/solid-start/basic-solid-query/src/routes/users.$userId.tsx around lines 9
to 11, errors from context.queryClient.ensureQueryData are becoming route errors
instead of rendering the notFoundComponent; wrap the ensureQueryData call in a
try/catch, detect 404s by checking error.status === 404 or
error.response?.status === 404, and when detected throw notFound() (imported
from 'solid-start') so the notFoundComponent renders and the 404 status is
preserved; for non-404 errors rethrow the original error.

Comment on lines +14 to +16
notFoundComponent: () => {
return <NotFound>User not found</NotFound>
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

notFoundComponent only triggers on notFound() — verify after applying the loader change.

After implementing the loader change above, confirm that requesting a non-existent user renders this component.


🏁 Script executed:

# Expect: "User not found" NotFound UI
# Example (adjust URL/port to your e2e env):
curl -i http://localhost:<port>/users/999999

Length of output: 50


I need to inspect the codebase to verify the loader implementation and understand how the notFoundComponent is supposed to trigger. Let me explore the file structure and the loader logic.


🏁 Script executed:

#!/bin/bash
# Examine the full route file to see the loader implementation
cat "e2e/solid-start/basic-solid-query/src/routes/users.\$userId.tsx"

Length of output: 1114


I can see the loader currently doesn't call notFound(). Let me inspect the userQueryOptions function to understand how it handles missing users:


🏁 Script executed:

#!/bin/bash
# Find and examine the userQueryOptions function
find e2e/solid-start/basic-solid-query -name "*users*" -type f | head -20

Length of output: 352



🏁 Script executed:

#!/bin/bash
# Examine the userQueryOptions function
cat "e2e/solid-start/basic-solid-query/src/utils/users.tsx"

Length of output: 875



🏁 Script executed:

#!/bin/bash
# Examine the API endpoint that fetches individual users
cat "e2e/solid-start/basic-solid-query/src/routes/api/users.\$id.ts"

Length of output: 935


Loader must catch the query error and call notFound() to trigger the notFoundComponent.

The current loader doesn't handle the error thrown by ensureQueryData(). When a non-existent user is requested, the API returns a 404, but the loader allows the error to propagate uncaught rather than calling notFound().

The loader needs modification:

loader: async ({ context, params: { userId } }) => {
  try {
    await context.queryClient.ensureQueryData(userQueryOptions(userId))
  } catch {
    throw new NotFoundError()
  }
},

Or use solid-router's notFound() function directly if available. Once this change is applied, the notFoundComponent will render for missing users.

🤖 Prompt for AI Agents
In e2e/solid-start/basic-solid-query/src/routes/users.$userId.tsx around lines
14 to 16, the loader does not catch errors from ensureQueryData and so a 404
from the API bubbles up instead of rendering the notFoundComponent; update the
loader to wrap the ensureQueryData call in a try/catch and on error call the
router's notFound() (or throw a NotFoundError) so the notFoundComponent is
triggered for missing users.

Comment on lines +9 to +27
const tags = [
{ title },
{ name: 'description', content: description },
{ name: 'keywords', content: keywords },
{ name: 'twitter:title', content: title },
{ name: 'twitter:description', content: description },
{ name: 'twitter:creator', content: '@tannerlinsley' },
{ name: 'twitter:site', content: '@tannerlinsley' },
{ name: 'og:type', content: 'website' },
{ name: 'og:title', content: title },
{ name: 'og:description', content: description },
...(image
? [
{ name: 'twitter:image', content: image },
{ name: 'twitter:card', content: 'summary_large_image' },
{ name: 'og:image', content: image },
]
: []),
]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Meta tags with undefined content values will be included.

When description or keywords are not provided, their corresponding meta tags will have content: undefined. This could result in invalid or empty meta tags in the rendered HTML.

Apply this diff to filter out tags with undefined content values:

   const tags = [
     { title },
     { name: 'description', content: description },
     { name: 'keywords', content: keywords },
     { name: 'twitter:title', content: title },
     { name: 'twitter:description', content: description },
     { name: 'twitter:creator', content: '@tannerlinsley' },
     { name: 'twitter:site', content: '@tannerlinsley' },
     { name: 'og:type', content: 'website' },
     { name: 'og:title', content: title },
     { name: 'og:description', content: description },
     ...(image
       ? [
           { name: 'twitter:image', content: image },
           { name: 'twitter:card', content: 'summary_large_image' },
           { name: 'og:image', content: image },
         ]
       : []),
-  ]
+  ].filter(tag => {
+    if ('title' in tag) return true
+    return tag.content !== undefined
+  })

   return tags
🤖 Prompt for AI Agents
In e2e/solid-start/basic-solid-query/src/utils/seo.ts around lines 9–27, the
tags array currently includes entries whose content may be undefined (e.g.,
description, keywords), producing invalid meta tags; after constructing the tags
array, filter out any tag objects that have a content property equal to
undefined and also ensure the title-only object is kept only when title is
defined — i.e., remove tags where ('content' in tag) and tag.content ===
undefined, and drop the title object if title is falsy.

Comment on lines +15 to +16
{ name: 'twitter:creator', content: '@tannerlinsley' },
{ name: 'twitter:site', content: '@tannerlinsley' },
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Hardcoded personal Twitter handles in e2e test utility.

These lines hardcode @tannerlinsley as the Twitter creator and site. Since this is an e2e test utility (not example code), these values should either be parameterized or use generic test values.

Apply this diff to make the Twitter handles configurable:

 export function seo(params: {
   title: string
   description?: string
   keywords?: string
   image?: string
+  twitterCreator?: string
+  twitterSite?: string
 }) {
-  const { title, description, keywords, image } = params
+  const { title, description, keywords, image, twitterCreator, twitterSite } = params

   const tags = [
     { title },
     { name: 'description', content: description },
     { name: 'keywords', content: keywords },
     { name: 'twitter:title', content: title },
     { name: 'twitter:description', content: description },
-    { name: 'twitter:creator', content: '@tannerlinsley' },
-    { name: 'twitter:site', content: '@tannerlinsley' },
+    { name: 'twitter:creator', content: twitterCreator },
+    { name: 'twitter:site', content: twitterSite },
     { name: 'og:type', content: 'website' },
🤖 Prompt for AI Agents
In e2e/solid-start/basic-solid-query/src/utils/seo.ts around lines 15-16, the
twitter:creator and twitter:site entries are hardcoded to '@tannerlinsley';
change them to configurable values by adding parameters (or reading
environment/config) such as twitterCreator and twitterSite to the SEO utility
function and use those values instead of literal strings, provide sensible
defaults for tests (e.g., '@test' or an empty handle), and update any
callers/tests to pass the test-specific handles or rely on the defaults.

Comment on lines +19 to +25
axios
.get<Array<User>>(DEPLOY_URL + '/api/users')
.then((r) => r.data)
.catch(() => {
throw new Error('Failed to fetch users')
}),
})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Don’t swallow HTTP status; map 404→notFound or rethrow with cause.

Catching and throwing a generic Error drops the 404, preventing route-level notFound handling.

Option A (prefer): translate 404 to notFound() and rethrow others.

+import { notFound } from '@tanstack/solid-router'
 ...
-        .then((r) => r.data)
-        .catch(() => {
-          throw new Error('Failed to fetch users')
-        }),
+        .then((r) => r.data)
+        .catch((e) => {
+          const status = (e as any)?.response?.status ?? (e as any)?.status
+          if (status === 404) throw notFound()
+          throw new Error('Failed to fetch users', { cause: e })
+        }),
 ...
-        .then((r) => r.data)
-        .catch(() => {
-          throw new Error('Failed to fetch user')
-        }),
+        .then((r) => r.data)
+        .catch((e) => {
+          const status = (e as any)?.response?.status ?? (e as any)?.status
+          if (status === 404) throw notFound()
+          throw new Error('Failed to fetch user', { cause: e })
+        }),

Option B: remove the .catch(...) blocks entirely and handle mapping to notFound() in the route loader (see route comment).

Also applies to: 31-37

🤖 Prompt for AI Agents
In e2e/solid-start/basic-solid-query/src/utils/users.tsx around lines 19-25 (and
similarly 31-37), the current .catch replaces all errors with a generic Error
and drops HTTP status; update the error handling to map a 404 to notFound() and
rethrow other errors with their original cause; specifically, in the axios.get
promise replace the generic .catch(() => throw new Error(...)) with logic that
checks the axios error response status (if 404 call notFound() immediately),
otherwise rethrow the original error (or throw a new Error while preserving the
original error as the cause) so upstream route loaders can handle non-404
errors; alternatively remove these local .catch blocks and perform the
404→notFound mapping in the route loader as noted in the comment.

Comment on lines +36 to +37
"test:unit": "exit 0; vitest",
"test:unit:dev": "pnpm run test:unit --watch",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Tests are effectively disabled (exit 0; vitest).

-    "test:unit": "exit 0; vitest",
+    "test:unit": "vitest",

If this is intentional for a draft, add a TODO and re-enable before merge.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"test:unit": "exit 0; vitest",
"test:unit:dev": "pnpm run test:unit --watch",
"test:unit": "vitest",
"test:unit:dev": "pnpm run test:unit --watch",
🤖 Prompt for AI Agents
In packages/solid-router-ssr-query/package.json around lines 36-37, the
"test:unit" script is prefixed with "exit 0;" which short-circuits and disables
unit tests; remove the "exit 0;" so the script simply runs "vitest" (i.e. change
to "test:unit": "vitest"), and if the disabling was intentional leave the
current line but add a TODO comment in the PR/issue tracker and mark tests to be
re-enabled before merge so CI still runs real tests.

Comment on lines +68 to +69
"eslint-plugin-solid": "^0.14.5"
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Move eslint plugin to devDependencies to avoid shipping it to consumers.

   "dependencies": {
-    "@tanstack/router-ssr-query-core": "workspace:*",
-    "eslint-plugin-solid": "^0.14.5"
+    "@tanstack/router-ssr-query-core": "workspace:*"
   },
   "devDependencies": {
+    "eslint-plugin-solid": "^0.14.5",
🤖 Prompt for AI Agents
In packages/solid-router-ssr-query/package.json around lines 68-69, the
eslint-plugin-solid entry is listed under dependencies and should be moved to
devDependencies so it isn't shipped to consumers; remove the
"eslint-plugin-solid": "^0.14.5" line from dependencies and add the same entry
under devDependencies (keeping the version), then run your package manager
(npm/yarn/pnpm) to update node_modules and lockfile so the change is reflected.

@birkskyum birkskyum force-pushed the solid-router-ssr-query branch from 197bd86 to acba783 Compare October 20, 2025 22:13
@birkskyum birkskyum requested a review from brenelz October 20, 2025 22:19
@birkskyum birkskyum merged commit 0231801 into main Oct 20, 2025
5 checks passed
@birkskyum birkskyum deleted the solid-router-ssr-query branch October 20, 2025 22:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants